package com.xlkj.ms.tools.aop.utils;

import com.xlkj.ms.tools.core.request.AbstractRequestWithValidate;
import org.hibernate.validator.HibernateValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Set;

/**
 * 参数校验工具类
 * @author zhuqifeng
 * @date 2021/11/10 14:08
 * @package com.xlkj.ms.tools.aop.utils
 */
@Component
public class ValidParamsUtils implements InitializingBean {

    private static Logger logger = LoggerFactory.getLogger(ValidParamsUtils.class);

    private static Validator validator;

    @Override
    public void afterPropertiesSet() throws Exception {
        validator = Validation.byProvider(HibernateValidator.class).configure().failFast(true).buildValidatorFactory().getValidator();
    }

    /**
     * 判断是否是基本类型
     * boolean, byte, char, short, int, long, float, 和double 等原始类型
     * String、BigDecimal、BigInteger
     * @param clazz
     * @return
     */
    private static boolean isPrimitive(Class clazz) {
        try {
            if ("java.lang.String".equals(clazz.getTypeName())
                    || "java.math.BigDecimal".equals(clazz.getTypeName())
                    || "java.math.BigInteger".equals(clazz.getTypeName())) {
                return true;
            }
            if (clazz.isPrimitive()) {
                return true;
            }
            return ((Class<?>) clazz.getField("TYPE").get(null)).isPrimitive();
        } catch (Exception e) {
            return false;
        }

    }

    /**
     * 注解参数校验
     *
     * @param object
     */
    public static void validateAnnotation(Object object, Class<?>... groups) throws IllegalArgumentException, IllegalAccessException {
        StopWatch watch = new StopWatch();
        watch.start();
        try{
            valid(object, groups);
            Class<?> clazz = object.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if (!isPrimitive(field.getClass())) {
                    valid(field.get(object), groups);
                }
            }
        }finally {
            watch.stop();
            logger.info("参数校验耗时：{}ms",watch.getTotalTimeMillis());
        }
    }

    private static void valid(Object object, Class<?>... groups) {
        Set<ConstraintViolation<Object>> constraintViolations = null;
        try {
            constraintViolations = validator.validate(object, groups);
        } catch (IllegalArgumentException e) {
        }
        if (null == constraintViolations) {
            return;
        }
        Iterator<ConstraintViolation<Object>> iterator = constraintViolations.iterator();

        // 是否有检验失败
        while (iterator.hasNext()) {
            // 检验失败消息
            throw new IllegalArgumentException(iterator.next().getMessage());
        }
        if (object instanceof AbstractRequestWithValidate) {
            AbstractRequestWithValidate baseRequest = (AbstractRequestWithValidate) object;
            baseRequest.validateLogic();
        } else if (object instanceof Iterable) {
            Iterator it = ((Iterable) object).iterator();
            while (it.hasNext()) {
                Object obj = it.next();
                if (obj instanceof AbstractRequestWithValidate) {
                    AbstractRequestWithValidate baseRequest = (AbstractRequestWithValidate) obj;
                    baseRequest.validateLogic();
                }
            }
        }
    }
}